package com.minisoft.utils;

import com.fasterxml.jackson.core.type.TypeReference;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.springframework.http.*;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author JueSu
 * @description: Http服务类
 * @date 2024/3/31 10:49
 */
@Slf4j
public class HttpClientService {
    private RestTemplate restTemplate;

    public HttpClientService() {
        this.restTemplate = buildRestTemplate();
    }
    public HttpClientService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public static RestTemplate buildRestTemplate() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(120, TimeUnit.SECONDS)
                .build();
        return new RestTemplate(new OkHttp3ClientHttpRequestFactory(okHttpClient));
    }

    /**
     * 发送Get请求，返回String类型
     * @param url
     * @param params
     * @return
     */
    public String doGet(String url, Map<String,Object> params, Map<String,String> headers) {
        return doGet(url, params, headers, String.class);
    }

    /**
     * 发送Get请求，可以指定返回类型（适用带泛型的返回类型）
     * @param url
     * @param params
     * @param headers
     * @param typeReference
     * @return
     * @param <T>
     */
    @SneakyThrows
    public <T> T doGet(String url, Map<String,Object> params, Map<String,String> headers, TypeReference<T> typeReference) {
        String s = doGet(url, params, headers);
        return JsonUtil.fromJson(s, typeReference);
    }

    /**
     * 发送Get请求，可以指定返回类型（适用普通的返回类型）
     * @param url
     * @param params
     * @param headers
     * @param responseType
     * @return
     * @param <T>
     */

    public <T> T doGet(String url, Map<String,Object> params, Map<String,String> headers,Class<T> responseType) {
        log.info("调用接口：{}，参数为：{}",url,JsonUtil.toJson(params));
        if (params != null && params.size() > 0) {
            StringBuilder sb = new StringBuilder();
            params.keySet().forEach(key -> {
                Object o = params.get(key);
                if (sb.length() > 0) {
                    sb.append("&");
                }
                if (o instanceof Collection) {
                    Collection col = (Collection) o;
                    col.forEach(item -> {
                        sb.append(key).append("=").append(item.toString()).append("&");
                    });
                    sb.deleteCharAt(sb.length() -1);
                } else {
                    sb.append(key).append("=").append(o.toString());
                }
            });
            String query = sb.toString();
            url += url.contains("?") ? "&" : "?" + query;
        }
        HttpHeaders httpHeaders = new HttpHeaders();
        if (headers != null && headers.size() > 0) {
            headers.forEach(httpHeaders::add);
        }
        HttpEntity<String> requestEntity = new HttpEntity<>(httpHeaders);
        ResponseEntity<T> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, responseType);
        T result = response.getBody();
        log.info("接口返回：{}", subString(result));
        return result;
    }

    /**
     * 写一个截取字符串长度的方法，最多500个字符
     */
    private String subString(Object obj) {
        if (obj == null) {
            return null;
        }
        String str = obj.toString();
        if (str.length() > 500) {
            return str.substring(0, 500);
        }
        return str;
    }
    /**
     * 通过Post方式请求服务，参数类型是Map，返回String类型
     * @param url
     * @param formMap
     * @return
     */
    public String doPost(String url,Map<String,String> formMap,Map<String,String> headers) {
        return doPost(url, formMap, headers, String.class);
    }

    /**
     * 通过Post方式请求服务，参数类型是Map，可以指定返回类型（适用带泛型的返回类型）
     * @param url
     * @param formMap
     * @param headers
     * @param typeReference
     * @return
     * @param <T>
     */
    @SneakyThrows
    public <T> T doPost(String url, Map<String,String> formMap, Map<String,String> headers, TypeReference<T> typeReference) {
        String s = doPost(url, formMap, headers);
        return JsonUtil.fromJson(s, typeReference);
    }

    /**
     * 通过Post方式请求服务，参数类型是Map，可以指定返回类型（适用普通不带泛型的返回类型）
     * @param url
     * @param formMap
     * @param headers
     * @param responseType
     * @return
     * @param <T>
     */
    public <T> T doPost(String url,Map<String,String> formMap,Map<String,String> headers,Class<T> responseType) {
        log.info("调用接口：{}，参数为：{}",url,JsonUtil.toJson(formMap));
        HttpHeaders httpHeaders = new HttpHeaders();
        if (headers != null && headers.size() > 0) {
            headers.forEach(httpHeaders::add);
        }
        //头部类型
        httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
        formMap.forEach(multiValueMap::add);
        //构造实体对象
        HttpEntity<MultiValueMap<String, String>> param = new HttpEntity<>(multiValueMap, httpHeaders);
        T result = restTemplate.postForObject(url,param,responseType);
        log.info("接口返回：{}", subString(result));
        return result;
    }

    /**
     * 通过Post方式请求服务，参数类型为请求体Body，返回String类型
     * @param url
     * @param jsonStr
     * @return
     */
    public String doPost(String url, String jsonStr, Map<String,String> headers) {
        return doPost(url, jsonStr, headers, String.class);
    }

    /**
     * 通过Post方式请求服务，参数类型为请求体Body，可以指定返回类型（适用普通不带泛型的返回类型）
     * @param url
     * @param jsonStr
     * @param headers
     * @param responseType
     * @return
     * @param <T>
     */
    public <T> T doPost(String url, String jsonStr, Map<String,String> headers,Class<T> responseType) {
        log.info("调用接口：{}，参数为：{}",url,jsonStr);
        HttpHeaders httpHeaders = new HttpHeaders();
        if (headers != null && headers.size() > 0) {
            headers.forEach(httpHeaders::add);
        }
        httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<String> entity = new HttpEntity<>(jsonStr, httpHeaders);
        T result = restTemplate.postForObject(url, entity,responseType);
        log.info("接口返回：{}", result);
        return result;
    }

    /**
     * 通过Post方式请求服务，参数类型为请求体Body，可以指定返回类型（适用于带泛型的返回类型）
     * @param url
     * @param jsonStr
     * @param headers
     * @param typeReference
     * @return
     * @param <T>
     */
    @SneakyThrows
    public <T> T doPost(String url, String jsonStr, Map<String,String> headers, TypeReference<T> typeReference) {
        String s = doPost(url, jsonStr, headers, String.class);
        return JsonUtil.fromJson(s, typeReference);
    }

}
